/**
 * Copyright (C), 2015-2021, XXX有限公司
 * FileName: XjfWorkOrderServiceImpl
 * Author:   Administrator
 * Date:     2021/8/6 0006 11:48
 * Description:
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package cn.hxlc.tie.demo.modular.jf.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hxlc.tie.demo.core.consumer.CueParamConsumer;
import cn.hxlc.tie.demo.core.enums.WorkOrderEnum;
import cn.hxlc.tie.demo.modular.jf.entity.*;
import cn.hxlc.tie.demo.modular.jf.mapper.XjfWorkOrderMapper;
import cn.hxlc.tie.demo.modular.jf.model.params.*;
import cn.hxlc.tie.demo.modular.jf.model.result.XjfInStoreResult;
import cn.hxlc.tie.demo.modular.jf.model.result.XjfReportResult;
import cn.hxlc.tie.demo.modular.jf.model.result.XjfReqMaterialResult;
import cn.hxlc.tie.demo.modular.jf.model.result.XjfWorkOrderResult;
import cn.hxlc.tie.demo.modular.jf.service.*;
import cn.hxlc.tie.demo.modular.xjf.testEquipment.service.dpTestService;
import cn.hxlc.tie.libs.mp.page.PageFactory;
import cn.hxlc.tie.model.exp.ServiceException;
import cn.hxlc.tie.model.page.PageResult;
import cn.hxlc.tie.system.api.model.QueryCueparamParam;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.base.Joiner;
import com.google.gson.JsonArray;
import org.apache.catalina.webresources.ClasspathURLStreamHandler;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.*;

/**
 * 〈一句话功能简述〉<br> 
 * 〈实现类〉
 *
 * @author jf.xu
 * @create 2021/8/6 0006
 * @since 1.0.0
 */
@Service
@Transactional
public class XjfWorkOrderServiceImpl extends ServiceImpl<XjfWorkOrderMapper, XjfWorkOrder> implements XjfWorkOrderService {

    @Autowired
    private XjfWorkOrderEntryService xjfWorkOrderEntryService;

    @Autowired
    private XjfWorkOrderService xjfWorkOrderService;

    @Autowired
    private XjfReqMaterialService xjfReqMaterialService;

    @Autowired
    private XjfInStoreService xjfInStoreService;

    //操作缓存
//    @Autowired
//    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private CueParamConsumer cueParamConsumer ;
    @Autowired
    JdbcTemplate jdbcTemplate;
    @Autowired
    NamedParameterJdbcTemplate jdbcTemplateN;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(XjfWorkOrderParam param){
        //创建订单
        if(param.getFcreatetime()==null){
            param.setFcreatetime(new Date());//初始化创建时间
        }
        param.setFbizdate(new Date());//固定业务日期

        XjfWorkOrder entity = getEntity(param);//把传回来的参数复制给实体类
        this.save(entity);//保存
        param.setFid(entity.getFid());//获取主表ID
        this.dealEntrys(param);//操作分录
    }

    @Override
    public PageResult<XjfWorkOrderResult> findPageBySpec(XjfWorkOrderParam param){
        Page pageContext = getPageContext();
        IPage<XjfWorkOrderResult> page = this.baseMapper.customPageList(pageContext, param);
        return new PageResult<>(page);
    }

    protected boolean getIsAutoTransmit(){
        //根据系统参数判断是否自动下达
        List<QueryCueparamParam> queryCueparamParamList1 = new ArrayList<>();
        QueryCueparamParam queryCueparamParam2 = new QueryCueparamParam();
        queryCueparamParam2.setAppcode("tie-demo");
        queryCueparamParam2.setHasEmptyCue(true);
        queryCueparamParam2.setFnumber("002");
        queryCueparamParamList1.add(queryCueparamParam2);
        Object obj1 = JSONArray.toJSON(queryCueparamParamList1);
        String str1 = cueParamConsumer.queryParam(obj1);
        Object resultData = JSONObject.parseObject(str1).getJSONArray("data").getString(0);
        System.out.println(resultData);

        if (resultData.equals("true")) {
           return true;
        }
        return false;
    }

    public void checkStatus(List<Long> ids,String msg,int status){
        QueryWrapper<XjfWorkOrder> wrapperWorkOrder = new QueryWrapper<>();
        wrapperWorkOrder.in("fid",ids);//要求列名为fid的在ids中
        wrapperWorkOrder.ne("fstatus",status);//ne：不等于
        int count = this.count(wrapperWorkOrder);//判断是否有符合条件的数据
        if(count>0){
            throw new ServiceException(500,msg);//抛出对应异常
        }
    }

    public void updateStatus(List<Long> ids,int status){
        //修改状态
        UpdateWrapper<XjfWorkOrder> updateWrapper = new UpdateWrapper<>();
        updateWrapper.in("fid",ids);//找到所有符合条件的ID对应的列
        updateWrapper.set("FSTATUS",status);//把状态修改为对应状态
        xjfWorkOrderService.update(updateWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchChangeSh(List<Long> ids) {
        checkStatus(ids,"操作失败，只有暂存状态的数据可审核",0);//先判断是否存在不符合条件的数据
        updateStatus(ids,WorkOrderEnum.SH.getValue());//修改状态
        if(getIsAutoTransmit()){
            batchChangeXd(ids);//如果系统参数为自动下达
        }
    }

    protected String getStringInByIds(Integer[] ids){
        //把integer类型的数组转换为String,并且用,分隔开
        StringBuffer sb = new StringBuffer();
        for(int i=0;i<ids.length;i++){
            if(i==0){
                sb.append(ids[i]);
            }else{
                sb.append(","+ids[i]);
            }
        }
        return sb.toString();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchChangeZc(List<Long> ids) {
        //反审核按钮
        QueryWrapper<XjfWorkOrder> wrapperWorkOrder = new QueryWrapper<>();
        wrapperWorkOrder.or(wrapper -> wrapper.ne("fstatus",1).ne("fstatus",2));
        //通过或语句拼接，存在于这两部分其中任意一部分的都满足条件
        wrapperWorkOrder.in("fid",ids);
        int count = this.count(wrapperWorkOrder);
        if(count>0){
            throw new ServiceException(500,"操作失败，存在非下达或审核状态的数据");
        }

        Map<String, Object> paramMap = new HashMap<String, Object>();
        //创建一个map集合
        paramMap.put("fworkorderid",ids);
        //给这个map集合中存储数据
        String sql = "select distinct b.fnumber from xjf_bd_report a inner join xjf_bd_work_order b on a.fworkorderid = b.fid where a.fworkorderid in (:fworkorderid)";//创建一个sql
        List<String> numbers = jdbcTemplateN.queryForList(sql,paramMap,String.class);
        //distinct 主要是可以避免出现重复元素
        //通过此方法根据id获取到对应的fnumber
        //主要是为了可以在前端返回对应业务出现问题的单据编码
        if(numbers.size()>0){
            throw new ServiceException(500, Joiner.on(",").join(numbers)+"下游存在汇报单据，无法变更");
        }

        sql = "select distinct b.fnumber from xjf_bd_instore a inner join xjf_bd_work_order b on a.fworkorderid = b.fid where a.fworkorderid in (:fworkorderid)";
        numbers = jdbcTemplateN.queryForList(sql,paramMap,String.class);
        if(numbers.size()>0){
            throw new ServiceException(500, Joiner.on(",").join(numbers)+"下游存在入库，无法变更");
        }

//        String sql = "select distinct b.fnumber from xjf_bd_report a inner join xjf_bd_work_order b on a.fworkorderid = b.fid where a.fworkorderid in (?)";
//        List<String> numbers = jdbcTemplate.queryForList(sql,new Object[]{getStringInByIds(fid)},String.class);
//        if(numbers.size()>0){
//            throw new ServiceException(500, Joiner.on(",").join(numbers)+"下游存在汇报单据，无法变更");
//        }

//        QueryWrapper<XjfReport> wrapperReport = new QueryWrapper<>();
//        wrapperReport.select("fworkorderid");
//        wrapperReport.in("fworkorderid",fid);
//        List<XjfReport> tempList = xjfReportService.list(wrapperReport);  //判断下游是否存在汇报单
//        if(tempList.size()>0){
//            throw new ServiceException(500,"下游存在汇报单据，无法变更");
//        }

        QueryWrapper<XjfReqMaterial> wrapperReq = new QueryWrapper<>();
        wrapperReq.in("fworkorderid",ids);
        count = xjfReqMaterialService.count(wrapperReq);  //判断下游是否存在领料单
        if (count != 0){
            throw new ServiceException(500,"下游存在领料单据，无法变更");
        }

        QueryWrapper<XjfInStore> wrapperInstore = new QueryWrapper<>();
        wrapperInstore.in("fworkorderid",ids);
        count = xjfInStoreService.count(wrapperInstore);  //判断下游是否存在入库单
        if (count != 0){
            throw new ServiceException(500,"下游存在入库单据，无法变更");
        }

        updateStatus(ids,WorkOrderEnum.ZC.getValue());

//        for(int i=0;i<fid.length;i++){
//            //下达状态的反审核
//            xjfWorkOrder = this.getById(Long.valueOf(fid[i]));
//if(xjfWorkOrder.getFstatus().getCode()==2){
//
//
//            QueryWrapper<XjfReport> wrapperReport = new QueryWrapper<>();
//            wrapperReport.eq("fworkorderid",xjfWorkOrder.getFid());
//            int count = xjfReportService.count(wrapperReport);  //判断下游是否存在汇报单
//            if (count != 0){
//                throw new ServiceException(500,"下游存在汇报单据，无法变更");
//            }
//
//            QueryWrapper<XjfReqMaterial> wrapperReq = new QueryWrapper<>();
//            wrapperReq.eq("fworkorderid",xjfWorkOrder.getFid());
//            int reqCount = xjfReqMaterialService.count(wrapperReq);  //判断下游是否存在领料单
//            if (reqCount != 0){
//                throw new ServiceException(500,"下游存在领料单据，无法变更");
//            }
//
//            QueryWrapper<XjfInStore> wrapperInstore = new QueryWrapper<>();
//            wrapperInstore.eq("fworkorderid",xjfWorkOrder.getFid());
//            int countInstore = xjfInStoreService.count(wrapperInstore);  //判断下游是否存在入库单
//            if (countInstore != 0){
//                throw new ServiceException(500,"下游存在入库单据，无法变更");
//            }
//
//            UpdateWrapper<XjfWorkOrder> updateWrapper = new UpdateWrapper<>();
//            updateWrapper.eq("fid",xjfWorkOrder.getFid());
//            updateWrapper.set("FSTATUS",WorkOrderEnum.ZC);
//            xjfWorkOrderService.update(null,updateWrapper);
//}
//else{
//    throw new ServiceException(500,"前置状态只允许为下达");
//}
//        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchChangeXd(List<Long> ids) {
        checkStatus(ids,"操作失败，前置状态只允许为审核状态",1);
        List<Object[]> param = new ArrayList<>();
            for(int i=0;i<ids.size();i++){
            param.add(new Object[]{ids.get(i)});
//                UpdateWrapper <XjfWorkOrder>  updateWrapper = new UpdateWrapper<>();
//                updateWrapper.set("FSTATUS",WorkOrderEnum.XD);
//                updateWrapper.eq("fid",xjfWorkOrder.getFid());
                //xjfWorkOrderService.update(xjfWorkOrder,updateWrapper);
                //xjfWorkOrderService.update(updateWrapper);
                //jdbcTemplate.update("update xjf_bd_work_order set FSTATUS = 2 where fid = ?",new Object[]{xjfWorkOrder.getFid()});
        }
        if(ids.size()>0){
            updateStatus(ids,WorkOrderEnum.XD.getValue());
            //jdbcTemplate.batchUpdate("update xjf_bd_work_order set FSTATUS = 2 where fid = ? and fid = ?",param);
        }
    }
   /*
   BigDecimal的具体用法，四则运算，四舍五入，商，余数，精度、比较。除法注意除零异常，除不尽异常（b.divide(new BigDecimal(3),2,BigDecimal.ROUND_HALF_UP);）
   QueryWapper
   UpdateWapper
   ServiceImpl
   批量的分录新增(数据的批量处理)
   按钮的业务分开
   对按钮的事务处理(toEnum)
   前端显示不能存在ID
   默认排序(FID逆序/创建时间逆序)
   */
    public void dealEntrys(XjfWorkOrderParam param){
        if(param.getEntrys()!=null){//分录不为空
            List<XjfWorkOrderEntryParam> entrys = param.getEntrys();
            XjfWorkOrderEntryParam entryParams;
            List<XjfWorkOrderEntry> workOrderEntryList= new ArrayList<>();
            //多线程处理，无序的
            //流循环
//            entrys.stream().forEach(tsm -> {
//                if(StringUtils.isEmpty(tsm.getFlot())){
//                    throw new ServiceException(500,"批号不能为空");
//                }
//                if(BeanUtil.isEmpty(tsm.getFunitid())){
//                    throw new ServiceException(500,"计量单位不能为空");
//                }
//                if(BeanUtil.isEmpty(tsm.getFinstoretype())){
//                    throw new ServiceException(500,"入库类型不能为空");
//                }
//                if(BeanUtil.isEmpty(tsm.getFmaterialid())){
//                    throw new ServiceException(500,"产品不能为空");
//                }
//                if(BeanUtil.isEmpty(tsm.getFqty())||(tsm.getFqty().compareTo(new BigDecimal(0)))<1){
//                    throw new ServiceException(500,"预计产量不能为空且必须大于0");
//                }
//                if(BeanUtil.isEmpty(tsm.getFplanenddate())){
//                    throw new ServiceException(500,"预计完工日期不能为空");
//                }
//                //注意这一行
//                XjfWorkOrderEntry xjfWorkOrderEntry = new XjfWorkOrderEntry();
//                BeanUtil.copyProperties(tsm,xjfWorkOrderEntry);
//                xjfWorkOrderEntry.setFparentid(param.getFid());//传入主表ID
//                workOrderEntryList.add(xjfWorkOrderEntry);
//            });

            XjfWorkOrderEntry xjfWorkOrderEntry;//定义一个分录实体
            //一个线程运行,有序的
            for(int i = 0;i<entrys.size();i++){
                //分录校验
                entryParams = entrys.get(i);//获取到分录集合
                if(StrUtil.isEmpty(entryParams.getFlot())){//判断String时有两种情况 1:为null,2:为空串
                    throw new ServiceException(500,"批号不能为空");
                }
                if(entryParams.getFunitid()==null){
                    throw new ServiceException(500,"计量单位不能为空");
                }
                if(entryParams.getFinstoretype()==null){
                    throw new ServiceException(500,"入库类型不能为空");
                }
                if(entryParams.getFmaterialid()==null){
                    throw new ServiceException(500,"产品不能为空");
                }
                if(entryParams.getFqty()==null||(entryParams.getFqty().compareTo(new BigDecimal(0)))<1){//compareto 比较两个bigdecimal，相等为0，前比后大返回1，否则返回-1
                    throw new ServiceException(500,"预计产量不能为空且必须大于0");
                }
                if(entryParams.getFplanenddate()==null){
                    throw new ServiceException(500,"预计完工日期不能为空");
                }
                //注意这一行
                xjfWorkOrderEntry = new XjfWorkOrderEntry();//进行实例化，在每次存分录数据时，都要初始化一次这个对象，否则所有的分录最终都会指向同一个对象
                BeanUtil.copyProperties(entryParams,xjfWorkOrderEntry);//
                xjfWorkOrderEntry.setFparentid(param.getFid());//传入主表ID
                workOrderEntryList.add(xjfWorkOrderEntry);
            }
            xjfWorkOrderEntryService.remove(new QueryWrapper<XjfWorkOrderEntry>().eq("fparentid",param.getFid()));//去除之前的旧数据
            this.xjfWorkOrderEntryService.saveBatch(workOrderEntryList);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDelete(List<Long> fid) {
        checkStatus(fid,"操作失败，只有暂存状态的数据可删除",0);
//        XjfWorkOrder info ;
//        for(int i=0;i<fid.length;i++){
//            info = this.getById(Long.valueOf(fid[i]));
//            if(info.getFstatus()!=null && (info.getFstatus().getCode()!=0)){
//                throw new ServiceException(500,"只有暂存状态的数据可删除！");
//            }
//            this.removeById(Long.valueOf(fid[i]));
//            //distDataConsumer.distData("tie-mdm-material", DistTypeConstants.DIST_SAVE,info.getFid());
//        }
        this.removeByIds(fid);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submitCloseReason(List<Long> ids,String fclosereason){

        QueryWrapper<XjfWorkOrder> wrapperWorkOrder = new QueryWrapper<>();

        wrapperWorkOrder.or(wrapper -> wrapper.ne("fstatus",0).ne("fstatus",1).ne("fstatus",2));
        wrapperWorkOrder.in("fid",ids);
        //通过或语句拼接，存在于这两部分其中任意一部分的都满足条件

        int count = this.count(wrapperWorkOrder);
        if(count>0){
            throw new ServiceException(500,"操作失败，存在已关闭的数据");
        }

        UpdateWrapper<XjfWorkOrder> updateWrapper = new UpdateWrapper<>();
        updateWrapper.in("fid",ids);//找到所有符合条件的ID对应的列
        updateWrapper.set("fclosereason",fclosereason);//把关闭原因修改为对应原因
        updateStatus(ids,3);
        xjfWorkOrderService.update(updateWrapper);

//        for(int i=0;i<fid.length;i++) {
//            xjfWorkOrder = this.getById(Long.valueOf((Integer)fid[i]));
//            if(xjfWorkOrder.getFstatus().getValue()>2){
//                throw new ServiceException(500,"订单已关闭，无法进行其他操作");
//            }
//            UpdateWrapper <XjfWorkOrder>  updateWrapper = new UpdateWrapper<>();
//            updateWrapper.set("FSTATUS",WorkOrderEnum.SDGB);
//            updateWrapper.set("FCLOSEREASON",fclosereason);
//            xjfWorkOrderService.update(xjfWorkOrder,updateWrapper);
//        }

    }

    @Override
    public XjfWorkOrderResult detail(Long fid) {
        XjfWorkOrderResult result = this.baseMapper.detail(fid);
        XjfWorkOrderEntryParam entryParam = new XjfWorkOrderEntryParam();
        entryParam.setFparentid(fid);

        result.setEntrys(xjfWorkOrderEntryService.findListBySpec(entryParam));
        return result;
    }

    private XjfWorkOrder getEntity(XjfWorkOrderParam param) {
        XjfWorkOrder entity = new XjfWorkOrder();
        BeanUtil.copyProperties(param, entity);
        return entity;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void update(XjfWorkOrderParam param){
        XjfWorkOrder oldEntity = getOldEntity(param);
        XjfWorkOrder newEntity = getEntity(param);
        BeanUtil.copyProperties(newEntity, oldEntity);
        this.updateById(oldEntity);
        this.dealEntrys(param);
    }

    private XjfWorkOrder getOldEntity(XjfWorkOrderParam param)
    {
        return this.getById(getKey(param));
    }

    private Serializable getKey(XjfWorkOrderParam param){
        return param.getFid();
    }

    private Page getPageContext() {
        Page page = PageFactory.defaultPage();
        page.addOrder(OrderItem.desc("fid"));//按照fid逆序
        return page;
    }
}
